import run_script_type from './run/type/script.js'
import run_module_type from './run/type/module.js'
import run_function_type from './run/type/function.js'
import run_call from './run/call.js'
import run_function from './run/function.js'
import run_import from './run/import.js'
import run_variable from './run/variable.js'
import run_set from './run/set.js'
import run_if from './run/if.js'
import run_return from './run/return.js'
import run_while from './run/while.js'
import run_for from './run/for.js'
import DebugInfo from '../../../debug/print.js'

const file_runs = [ run_script_type, run_module_type, run_function_type ]
const body_runs = [ run_import, run_call, run_function, run_variable, run_set, run_if, run_return, run_while, run_for ]

const init = (runtime, ast) => {
  if (!runtime.scopes.has(ast.filepath)) {
    runtime.scopes.set(ast.filepath, new Map())

    const scope = runtime.scopes.get(ast.filepath)

    const self = new Map()
    self.set('type', ast.type)
    self.set('filepath', ast.filepath)
    self.set('filename', ast.filename)

    scope.set('self', self)

    const constant = new Map()
    scope.set('constant', constant)

    const variable = new Map()
    scope.set('variable', variable)
  }
}

const interpreter = async (runtime, ast) => {
  const config = runtime.config

  if (config.get('PRINT_RUNTIME_BEFORE_RUN')) {
    const debugInfo = new DebugInfo('Runtime Before Run', ast.filepath)
    debugInfo.start()
    debugInfo.print(runtime)
    debugInfo.end()
  }

  init(runtime, ast)

  if (config.get('PRINT_RUNTIME_AFTER_INIT')) {
    const debugInfo = new DebugInfo('Runtime After Init', ast.filepath)
    debugInfo.start()
    debugInfo.print(runtime)
    debugInfo.end()
  }

  for (const run of file_runs) {
    await run(runtime, ast, body_runs)
  }

  if (config.get('PRINT_RUNTIME_AFTER_RUN')) {
    const debugInfo = new DebugInfo('Runtime After Run', ast.filepath)
    debugInfo.start()
    debugInfo.print(runtime)
    debugInfo.end()
  }

  if (runtime.return !== null) {
    return runtime.return
  }
}

export { init }
export default interpreter